#ifndef MAILBOX_H_INCLUDED
#define MAILBOX_H_INCLUDED

#include <Ape/MT/Mutex.h>
#include <Ape/Collections/Queue.h>
#include <Ape/MT/EWouldBlock.h>

namespace Ape {
	namespace MT {
		template <typename Letter_t>
		class MailBox {
			TYPE_NAME ("Ape::Collections::MailBox<Letter_t>")
		private:
			Ape::Collections::Queue<Letter_t> m_InternalQueue;
			Mutex m_Pender;
			Mutex m_Modifying;
		public:
			MailBox ();
			virtual ~MailBox();
			
			void Send(const Letter_t& letter);
			const Letter_t Receive(bool nonBlocking = false);
			
			void Purge();
		};
		
		
		
		template <typename Letter_t>
		MailBox<Letter_t>::MailBox() {}
		template <typename Letter_t>
		MailBox<Letter_t>::~MailBox() {}
		
		template <typename Letter_t>
		void MailBox<Letter_t>::Purge() {
			MutexLock lock (m_Modifying);
			m_InternalQueue.Purge();
		}
		
		template <typename Letter_t>
		void MailBox<Letter_t>::Send(const Letter_t& letter) {
			Ape::MT::MutexLock lock(m_Modifying);
			m_InternalQueue.Enq(letter);
			m_Pender.Unlock();
		}
		
		template <typename Letter_t>
		const Letter_t MailBox<Letter_t>::Receive(bool nonBlocking) {
			Ape::MT::MutexLock lock(m_Modifying);
			if (!m_InternalQueue.get_Count()) {
				if (nonBlocking)
					throw Ape::MT::EWouldBlock(L"Mailbox is empty");
				lock.ForceUnlock();
				m_Pender.Lock();
				if (!m_InternalQueue.get_Count())
					m_Pender.Lock();
			}
			Letter_t letter = m_InternalQueue.Deq();
			return letter;
		}
	}
}

#endif // MAILBOX_H_INCLUDED
